package com.Database;

import java.io.File;
import java.util.ArrayList;
import java.util.Vector;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

import com.CustomControl.MyImageView;
import com.DataStructure.Node;
import com.DataStructure.Tile;

public class DBAdapter extends SQLiteOpenHelper {

	/** The name of the database file on the file system */
	public static final String DATABASE_NAME = "hanoi_map_data";
	/** The version of the database that this class understands. */
	public static final int DATABASE_VERSION = 5;

	@SuppressWarnings("unused")
	private Context mContext;

	private SQLiteDatabase db;

	public DBAdapter(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
		this.mContext = context;
		try {
			db = getWritableDatabase();
		} catch (Exception e) {
			db = getReadableDatabase();
		} finally {

			File sdcard = Environment.getExternalStorageDirectory();

			String dbfile = sdcard.getAbsolutePath() + File.separator
					+ DATABASE_NAME;
			db = SQLiteDatabase.openDatabase(dbfile, null,
					SQLiteDatabase.NO_LOCALIZED_COLLATORS);

		}
	}

	@Override
	public void onCreate(SQLiteDatabase db) {

	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

	}

	@Override
	public synchronized void close() {
		if (db != null) {
			db.close();
			super.close();
		}
	}

	public boolean test_db() {
		if (db != null)
			return true;
		else
			return false;
	}

	public Tile getTitle(int x_input, int y_input) {
		Tile tile = null;
		Cursor my_cursor = db.query(
				"tiles",
				new String[] { "x", "y", "z", "s", "image" },
				"x = ? AND y = ?",
				new String[] { Integer.toString(x_input),
						Integer.toString(y_input) }, null, null, null);
		if (my_cursor != null) {
			my_cursor.moveToPosition(0);
			int x = my_cursor.getInt(my_cursor.getColumnIndex("x"));
			int y = my_cursor.getInt(my_cursor.getColumnIndex("y"));
			int z = my_cursor.getInt(my_cursor.getColumnIndex("z"));
			int s = my_cursor.getInt(my_cursor.getColumnIndex("s"));
			byte[] image = my_cursor.getBlob(4);
			Bitmap image_bitmap = convertByteArrayToBitmap(image);
			tile = new Tile(x, y, z, s, image_bitmap);
		}

		if (my_cursor != null) {
			my_cursor.close();
		}

		return tile;
	}

	public ArrayList<Tile> getAllTile() {
		ArrayList<Tile> list = new ArrayList<Tile>();
		int rowNum = 8;
		Cursor my_cursor = db.query("tiles", new String[] { "x", "y", "z", "s",
				"image" }, null, null, null, null, null);
		if (my_cursor != null) {
			for (rowNum = 10; rowNum >= 0; rowNum--) {
				my_cursor.moveToPosition(rowNum);
				int x = my_cursor.getInt(my_cursor.getColumnIndex("x"));
				int y = my_cursor.getInt(my_cursor.getColumnIndex("y"));
				int z = my_cursor.getInt(my_cursor.getColumnIndex("z"));
				int s = my_cursor.getInt(my_cursor.getColumnIndex("s"));
				byte[] image = my_cursor.getBlob(4);
				Bitmap image_bitmap = convertByteArrayToBitmap(image);
				Tile tile = new Tile(x, y, z, s, image_bitmap);
				list.add(tile);
			}
		}

		if (my_cursor != null) {
			my_cursor.close();
		}

		return list;
	}

	public ArrayList<Tile> getAroundPossition(int id_x, int id_y, int z) {
		ArrayList<Tile> result = new ArrayList<Tile>();
		Cursor mCursor = db.query(
				"tiles",
				new String[] { "x", "y", "z", "s", "image" },
				" x > ? AND x < ? AND y > ? AND y < ? AND z = ?",
				new String[] { Integer.toString(id_x - 3),
						Integer.toString(id_x + 3), Integer.toString(id_y - 3),
						Integer.toString(id_y + 3), Integer.toString(z) },
				null, null, null);
		if (mCursor != null) {
			while (mCursor.moveToNext()) {
				int X = mCursor.getInt(mCursor.getColumnIndex("x"));
				int Y = mCursor.getInt(mCursor.getColumnIndex("y"));
				int Z = mCursor.getInt(mCursor.getColumnIndex("z"));
				int S = mCursor.getInt(mCursor.getColumnIndex("s"));
				byte[] image = mCursor.getBlob(4);
				Bitmap image_bitmap = convertByteArrayToBitmap(image);
				Tile tile = new Tile(X, Y, Z, S, image_bitmap);
				result.add(tile);

			}
			mCursor.close();
			return result;
		}
		return null;
	}

	private ArrayList<Tile> getArea(int topX, int leftY, int bottonX,
			int rightY, int zoomLv) {
		ArrayList<Tile> result = new ArrayList<Tile>();
		Cursor mCursor = db.query(
				"tiles",
				new String[] { "x", "y", "z", "s", "image" },
				" x >= ? AND x < ? AND y >= ? AND y < ? AND z = ?",
				new String[] { Integer.toString(topX),
						Integer.toString(bottonX), Integer.toString(leftY),
						Integer.toString(rightY), Integer.toString(zoomLv) },
				null, null, null);
		if (mCursor != null) {
			while (mCursor.moveToNext()) {
				int X = mCursor.getInt(mCursor.getColumnIndex("x"));
				int Y = mCursor.getInt(mCursor.getColumnIndex("y"));
				int Z = mCursor.getInt(mCursor.getColumnIndex("z"));
				int S = mCursor.getInt(mCursor.getColumnIndex("s"));
				byte[] image = mCursor.getBlob(4);
				Bitmap image_bitmap = convertByteArrayToBitmap(image);
				Tile tile = new Tile(X, Y, Z, S, image_bitmap);
				result.add(tile);
			}
			mCursor.close();
			return result;
		}
		return null;
	}

	public ArrayList<Tile> getTiles(int tilesMove, int centerTileX,
			int centerTileY, int direction, int zoomLv) {
		if (direction == MyImageView.WIDTH) {
			if (tilesMove > 0) {
				return getArea(centerTileX / 256 + 3, centerTileY / 256 - 2,
						centerTileX / 256 + 4, centerTileY / 256 + 3, zoomLv);
			} else if (tilesMove < 0) {
				return getArea(centerTileX / 256 - 3, centerTileY / 256 - 2,
						centerTileX / 256 - 2, centerTileY / 256 + 3, zoomLv);
			}

		} else if (direction == MyImageView.HEIGH) {
			if (tilesMove > 0) {
				return getArea(centerTileX / 256 - 2, centerTileY / 256 + 3,
						centerTileX / 256 + 3, centerTileY / 256 + 3
								+ tilesMove, zoomLv);
			} else if (tilesMove < 0) {
				return getArea(centerTileX / 256 - 2, centerTileY / 256 - 2
						+ tilesMove, centerTileX / 256 + 3,
						centerTileY / 256 - 2, zoomLv);
			}
		}
		return null;
	}

	public Bitmap convertByteArrayToBitmap(byte[] input) {

		Bitmap bitmap_image = null;
		bitmap_image = BitmapFactory.decodeByteArray(input, 0, input.length);

		return bitmap_image;
	}

	public Node getNearestNode(double lat, double lng) {
		Cursor my_cursor = db
				.query("nodes",
						new String[] { "id", "lat", "lng", "next_nodes" },
						"lat >= ? AND lat <= ? AND lng >= ? AND lng <= ? AND next_nodes != ?",
						new String[] { Double.toString(lat - 0.01),
								Double.toString(lat + 0.01),
								Double.toString(lng - 0.01),
								Double.toString(lng + 0.01), "null" }, null,
						null, null);
		Node nearest_node = new Node();
		double shortest_distan = Double.MAX_VALUE;
		while (my_cursor.moveToNext()) {
			double temp_node_lat = my_cursor.getDouble(my_cursor
					.getColumnIndex("lat"));
			double temp_node_lng = my_cursor.getDouble(my_cursor
					.getColumnIndex("lng"));
			double new_distance = Math.pow(temp_node_lat - lat, 2)
					+ Math.pow(temp_node_lng - lng, 2);
			if (new_distance < shortest_distan) {
				shortest_distan = new_distance;
				nearest_node = new Node(my_cursor.getInt(0), temp_node_lat,
						temp_node_lng, my_cursor.getString(3));
			}

		}
		return nearest_node;
	}

	public Vector<Node> getNextNodes(Node picked, Node end_node) {
		Vector<Node> result = new Vector<Node>();
		String str_next_nodes = picked.getNextNodes();
		String selection = "";
		Vector<String> vtr_selection_args = new Vector<String>();

		int id = 0;
		for (int i = 0; i < str_next_nodes.length(); i++) {
			if (str_next_nodes.charAt(i) == ',') {
				if (selection.equals("")) {
					selection += "= ?";
				} else {
					selection += " OR id = ?";
				}

				vtr_selection_args.add(str_next_nodes.substring(id, i));
				i++;
				id = i + 1;
			}
		}
		String[] selection_args = new String[vtr_selection_args.size()];
		for (int i = 0; i < selection_args.length; i++) {
			selection_args[i] = vtr_selection_args.elementAt(i);
		}
		String query = "SELECT * FROM nodes WHERE id " + selection;
		Cursor my_cursor = db.rawQuery(query, selection_args);
		while (my_cursor.moveToNext()) {
			Node new_node = new Node();
			new_node.setId(my_cursor.getInt(0));
			new_node.setLat(my_cursor.getDouble(1));
			new_node.setLng(my_cursor.getDouble(2));
			new_node.setDistanceTraveled(distanceTraveled(picked, new_node));
			new_node.setDistanceToEndNode(distanceToEndNode(new_node, end_node));
			new_node.setNextNodes(my_cursor.getString(3));
			new_node.setParent(picked.getId());
			result.add(new_node);
		}
		return result;
	}

	private double distanceTraveled(Node from, Node to) {
		// TODO return distance was travel of node to
		return from.getDistanceTraveled()
				+ Math.sqrt(Math.pow(to.getLat() - from.getLat(), 2)
						+ Math.pow(to.getLng() - from.getLng(), 2));
	}

	private double distanceToEndNode(Node from, Node end_node) {
		// TODO return distance between from and end node
		return Math.sqrt(Math.pow(end_node.getLat() - from.getLat(), 2)
				+ Math.pow(end_node.getLng() - from.getLng(), 2));
	}
}
